/*******************************************************
PROGRAM NAME - Main  - serves as a driver function
PROGRAMMER - Trenton Nall, 423-37-8734
USAGE - run program to see a demonstration
COMPILE - see instructions in text file
SYSTEM - Linux
DATE - 10/30/2012
DESCRIPTION - This program is a driver that performs tests on the 3 classes designed
	per the specification for homework 7.
*******************************************************/

#include <iostream>
#include "BasicQueue.h"
#include "Queue.h"
#include "ComplexNumber.h"
#include <assert.h>
#include <cmath>
using namespace std;

void testQuestion1Queue();
void testQuestion2Queue();
void testQuestion3ComplexNumber();
bool equals(double value1, double value2);

/**************************************************************
Function main
PURPOSE: Performs the testing required for homework 7
PARAMETERS: none
CALLED BY: operating system
SIDE EFFECTS: This function changes no global variables or
parameters.
***************************************************************/
int main(int argc, char *argv[]) {

	cout << "\nTrenton Nall\nHomework 7\nTesting...\n\n\n";

	// test question 1 queue
	testQuestion1Queue();

	// test question 2 queue
	testQuestion2Queue();

	// test question 3 queue
	testQuestion3ComplexNumber();

	cout << "Press the Enter key to continue...";
	cin.ignore();
	cout << endl;

	return 0;
}

/**************************************************************
Function testQuestion1Queue
PURPOSE: Performs the testing for the basic queue for question 1
PARAMETERS: none
CALLED BY: main
SIDE EFFECTS: This function changes no global variables or
parameters.
***************************************************************/
void testQuestion1Queue() {

	BasicQueue *test = new BasicQueue();

	// test BasicQueue from Question 1
	cout << "BasicQueue from Question 1 is Testing..." << endl;

	// make sure that size() works correctly
	assert(test->size() == 0);

	// test enqueue operation
	test->enqueue(4);
	test->enqueue(5);
	test->enqueue(-66);
	test->enqueue(7);

	// make sure four items were queued up corrently and that size() works
	assert(test->size() == 4);

	// make sure that a single dequeue is performed correctly
	assert(test->dequeue() == 4 && test->size() == 3);

	// make sure queue is operating FIFO and generating correct numbers
	assert(test->dequeue() == 5);
	assert(test->dequeue() == -66);
	assert(test->dequeue() == 7);

	// make sure that queue is now empty as it should be
	assert(test->size() == 0);

	// make sure that an exception is thrown when you attempt to dequeue from an empty queue
	try {
		test->dequeue();

		// fail test if exception wasn't thrown
		assert(false);
	} catch (...) {}

	// add some items to the queue then verify that the queue empties correctly
	test->enqueue(88);
	test->enqueue(90);
	test->enqueue(123);

	// make sure that the queue contains items
	assert(test->size() > 0);

	// now empty the queue and make sure that it contains no elements afterwords
	test->empty();
	assert(test->size() == 0);

	cout << "All tests of BasicQueue for Question 1 Passed!\n\n\n";
}

/**************************************************************
Function testQuestion2Queue
PURPOSE: Performs the testing for the Queue from question 2
PARAMETERS: none
CALLED BY: main
SIDE EFFECTS: This function changes no global variables or
parameters.
***************************************************************/
void testQuestion2Queue() {

	Queue<double> *test = new Queue<double>();

	// test BasicQueue from Question 1
	cout << "Queue from Question 2 is Testing..." << endl;

	// make sure that size() works correctly
	assert(test->size() == 0);

	// test enqueue operation
	test->enqueue(4.0);
	test->enqueue(556.99);
	test->enqueue(60123.3333);
	test->enqueue(-7.9);

	// make sure four items were queued up correctly and that size() works
	assert(test->size() == 4);

	// make sure that a single dequeue is performed correctly
	assert(test->dequeue() == 4 && test->size() == 3);

	// make sure queue is operating FIFO and generating correct numbers
	assert(test->dequeue() == 556.99);
	assert(test->dequeue() == 60123.3333);
	assert(test->dequeue() == -7.9);

	// make sure that queue is now empty as it should be
	assert(test->size() == 0);

	// make sure that an exception is thrown when you attempt to dequeue from an empty queue
	try {
		test->dequeue();

		// fail test if exception wasn't thrown
		assert(false);
	} catch (...) {}

	// add some items to the queue then verify that the queue empties correctly
	test->enqueue(88.45);
	test->enqueue(90);
	test->enqueue(123.7);

	// make sure that the queue contains items
	assert(test->size() > 0);

	// now empty the queue and make sure that it contains no elements afterwords
	test->empty();
	assert(test->size() == 0);

	cout << "All tests of Queue for Question 2 Passed!\n\n\n";
}


/**************************************************************
Function testQuestion3ComplexNumber
PURPOSE: Performs the testing for the ComplexNumber class from question 3
PARAMETERS: none
CALLED BY: main
SIDE EFFECTS: This function changes no global variables or
parameters.
***************************************************************/
void testQuestion3ComplexNumber() {
	cout << "ComplexNumber from Question 3 is Testing..." << endl;

	// test construction of ComplexNumber from two constant floating point constants
	ComplexNumber *testInit = new ComplexNumber(4.0, 5.6);

	// make sure ComplexNumber was correctly constructed correctly
	assert(equals(testInit->getReal(), 4.0));
	assert(equals(testInit->getImaginary(), 5.6));

	ComplexNumber *test = new ComplexNumber(3.2, 45.6);

	// test that methods for extraction for real and imaginary
	// parts of complex # work correctly
	assert(equals(test->getReal(), 3.2));
	assert(test->getImaginary() == 45.6);

	// test that complex number addition works correctly
	ComplexNumber *test1 = new ComplexNumber(2, 3.2);
	ComplexNumber *test2 = new ComplexNumber(3, 5);
	test1->add(*test2);

	// verify that addition was performed correctly
	assert(equals(test1->getReal(), 5));
	assert(equals(test1->getImaginary(), 8.2));


	// test that ComplexNumber subtraction works correctly
	ComplexNumber *test3 = new ComplexNumber(2.1, 45.6);
	ComplexNumber *test4 = new ComplexNumber(3, 7.3);
	test3->subtract(*test4);

	// verify that subtraction was performed correctly
	assert(equals(test3->getReal(), -.9));
	assert(equals(test3->getImaginary(), 38.3));


	// test that multiplication works correctly
	ComplexNumber *test5 = new ComplexNumber(34, 55);
	ComplexNumber *test6 = new ComplexNumber(34.2, 78);
	test5->multiplyBy(*test6);

	// verify that multiplication works correctly
	assert(equals(test5->getReal(), -3127.2));
	assert(equals(test5->getImaginary(), 4533));


	// test that division works correctly
	ComplexNumber *test7 = new ComplexNumber(99.9, -8);
	ComplexNumber *test8 = new ComplexNumber(56, 44.3);
	test7->divideBy(*test8);

	// verify that division works correctly
	assert(equals(test7->getReal(), 1.027755));
	assert(equals(test7->getImaginary(), -.955885));

	cout << "All tests of ComplexNumber for Question 3 Passed!\n\n\n";
}

/**************************************************************
Function equals
PURPOSE: Determines whether or not two floating point #'s should be considered equal
PARAMETERS: none
CALLED BY: main
SIDE EFFECTS: This function changes no global variables or
parameters.
***************************************************************/
bool equals(double value1, double value2) {
	// determine the difference between the values
	double diff = abs(value1 - value2);

	// threshold that determines whether or not two floating point
	// numbers are considered equal
	double threshold = .01;

	// determine whether or not the two floating point #'s are equal
	// within a boundary
	return (diff < threshold) ? true : false;
}
